package uk.ac.manchester.cs.haphan.modbench;

import java.io.File;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.Set;
import org.semanticweb.owlapi.apibinding.OWLManager;
import org.semanticweb.owlapi.model.IRI;
import org.semanticweb.owlapi.model.OWLAxiom;
import org.semanticweb.owlapi.model.OWLEntity;
import org.semanticweb.owlapi.model.OWLOntology;
import org.semanticweb.owlapi.model.OWLOntologyCreationException;
import org.semanticweb.owlapi.model.OWLOntologyManager;
import org.semanticweb.owlapi.model.OWLOntologyStorageException;
import org.semanticweb.owlapi.reasoner.OWLReasoner;
import uk.ac.manchester.cs.owlapi.modularity.ModuleType;
import uk.ac.manchester.cs.owlapi.modularity.SyntacticLocalityModuleExtractor;

/**
 *
 * @author Ha Phan
 * The University of Manchester
 * phanh[at]cs.man.ac.uk
 */
public class ModuleGenerator {

    private FileHandler fileHandler;
    private OWLOntologyManager manager;
    public static final int REASONER_FACTPLUSPLUS = 1;
    public static final int REASONER_HERMIT = 2;
    public static final int REASONER_PELLET = 3;
    private int defaultReasoner;
    private boolean verbose = true;

    public ModuleGenerator(int defaultReasoner) {
        this.fileHandler = new FileHandler("data");
        this.manager = this.manager = OWLManager.createOWLOntologyManager();
        if (defaultReasoner < 1 || defaultReasoner > 3) {
            this.defaultReasoner = 1;
        } else {
            this.defaultReasoner = defaultReasoner;
        }
    }

    public void generate() {
        ArrayList<File> ontoFiles = this.fileHandler.getInputFiles();
        for (File f : ontoFiles) {
            this.generateModule(f);
        }
    }

    private OWLReasoner getReasoner(OWLOntology ontology) {
        ReasonerManager rm = new ReasonerManager();
        switch (this.defaultReasoner) {
            case REASONER_FACTPLUSPLUS:
                return rm.getFactPlusPlus(ontology);
            case REASONER_HERMIT:
                return rm.getHermiT(ontology);
            case REASONER_PELLET:
                return rm.getPellet(ontology);
            default:
                rm.getFactPlusPlus(ontology);
                break;
        }
        return null;
    }

    private void generateModule(File f) {
        try {
            File outputFolder = new File(this.fileHandler.getCurrentOutputFolder(), f.getName());
            OWLOntology ont = this.manager.loadOntologyFromOntologyDocument(f);
            Set<OWLEntity> sig = ont.getSignature();
            for (OWLEntity s : sig) {
                Set<OWLEntity> setSignature = new HashSet<OWLEntity>();
                setSignature.add(s);
                Set<OWLAxiom> axs = this.extract(setSignature, ont, ModuleType.STAR);
                this.writeModuleToFile(axs, s, outputFolder);

            }
        } catch (OWLOntologyCreationException ontoException) {
            this.printError(ontoException);
        }
    }

    private void writeModuleToFile(Set<OWLAxiom> axs, OWLEntity signature, File outputFolder) {
        //Module name: EntityType.SignatureName.owl
        if(axs.size() < 5) return;
        String moduleFileName = String.format("%s.%s.owl", signature.getEntityType().toString(), signature.getIRI().getFragment());//;
        try {
            OWLOntology onto = this.manager.createOntology(axs);
            File moduleFile = new File(outputFolder, moduleFileName);
            //moduleFile.createNewFile();
            this.manager.saveOntology(onto, IRI.create(moduleFile));
        }catch(OWLOntologyCreationException ontoException){
            this.printError(ontoException);
        //}catch(IOException ioException){
        //    this.printError(ioException);
        }catch(OWLOntologyStorageException ontoSaveException){
            this.printError(ontoSaveException);
        }
    }

    public Set<OWLAxiom> extract(Set<OWLEntity> signature, OWLOntology ontology, ModuleType moduleType) throws OWLOntologyCreationException {

        SyntacticLocalityModuleExtractor extractor = new SyntacticLocalityModuleExtractor(this.manager, ontology, moduleType);

        return extractor.extract(signature);
    }

    private void printError(Exception e) {
        if (this.verbose) {
            System.out.println(e.getMessage());
        }
    }
}
